import { DEBUG } from "cc/env";
import c3d from "../tool/cc";
import { Resource } from "./Resource";

/**
 * 资源加载器
 */
export default class ResourceLoader {

    /** 加载资源数据 */
    private _resources: Map<string, Resource.Data> = new Map<string, Resource.Data>();
    /**当前已经加载的资源数量 */
    private _loadedCount: number = 0;

    /**加载完成后的数据，为了方便释放时精准释放，没加载成功的资源，不在做释放的判断 */
    private _loadedResource: Map<string, Resource.Info> = new Map<string, Resource.Info>();

    /**当前是否正在加载资源 */
    private _isLoading: boolean = false;

    /**标识 */
    tag: string = null!;

    /**加载完成回调 */
    private onLoadComplete: (error: Resource.LoaderError) => void;

    /**加载进度 */
    onLoadProgress: (loadedCount: number, toatl: number, data: Resource.CacheData) => void;

    /**实现类必须给个需要加载资源  */
    private getLoadResource: () => Resource.Data[];

    /** * 加载资源 */
    loadResources() {
        if (!this.getLoadResource) {
            if (DEBUG) c3d.error("未指定 getLoadResources 函数");
            this.onLoadComplete && this.onLoadComplete(Resource.LoaderError.NO_FOUND_LOAD_RESOURCE);
            return;
        }

        let res = this.getLoadResource();
        if (!res) {
            if (DEBUG) c3d.error(`未指定加载资源`);
            this.onLoadComplete && this.onLoadComplete(Resource.LoaderError.NO_FOUND_LOAD_RESOURCE);
            return;
        }
        if (res.length <= 0) {
            if (DEBUG) c3d.Out.warning(`加载的资源为空`);
            this.onLoadComplete && this.onLoadComplete(Resource.LoaderError.NO_FOUND_LOAD_RESOURCE);
            return;
        }
        //如果正在加载中，防止重复调用
        if (this._isLoading) {
            if (DEBUG) c3d.Out.warning(`资源加载中，未完成加载`);
            this.onLoadComplete && this.onLoadComplete(Resource.LoaderError.LOADING);
            return;
        }
        if (this._resources.size > 0 && this.isLoadComplete()) {
            if (DEBUG) c3d.Out.warning(`资源已经加载完成，使用已经加载完成的资源`);
            this.onLoadComplete && this.onLoadComplete(Resource.LoaderError.SUCCESS);
            this.onLoadResourceComplete();
            return;
        }

        this._isLoading = true;
        //为防止重复，这里把资源放在一个map中
        res.forEach((value, index) => {
            if (value.url) {
                this._resources.set(value.url, value);
            } else if (value.dir) {
                this._resources.set(value.dir, value);
            } else {
                if (value.preloadView) this._resources.set(value.preloadView.getPrefabUrl(), value);
            }
        });

        this._loadedCount = 0;
        this._resources.forEach((value, key, source) => {
            if (value.preloadView) {
                GM.uiMgr.preload(value.preloadView, value.bundle as BUNDLE_TYPE).then((view) => {
                    let cache = new Resource.CacheData({ bundle: value.bundle, data: view as any });
                    cache.isLoaded = true;
                    if (value.preloadView)
                        cache.info.url = value.preloadView.getPrefabUrl();
                    this._onLoadResourceComplete(cache);
                })
            } else if (value.dir) {
                GM.assetMgr.loadDir(value.bundle as BUNDLE_TYPE, value.dir, <any>(value.type), <any>null, this._onLoadResourceComplete.bind(this));
            } else {
                GM.assetMgr.load(value.bundle as BUNDLE_TYPE, value.url as string, <any>(value.type), <any>null, this._onLoadResourceComplete.bind(this));
            }
        });
    }

    /**  * 卸载已经加载资源资源  */
    unLoadResources() {
        if (this._isLoading || this._resources.size <= 0) {
            //当前正在加载中
            if (this._isLoading) {
                c3d.warn("resources is loading , waiting for unload!!!");
            }
            return;
        }
        if (this._resources.size > 0) {
            this._resources.forEach((value) => {
                if (value.url) {
                    if (this._loadedResource.has(value.url)) {
                        let data = this._loadedResource.get(value.url);
                        if (data) {
                            GM.assetMgr.releaseAsset(data);
                        }
                        this._loadedResource.delete(value.url);
                    }
                } else if (value.dir) {
                    if (this._loadedResource.has(value.dir)) {
                        let data = this._loadedResource.get(value.dir);
                        if (data) {
                            GM.assetMgr.releaseAsset(data);
                        }
                        this._loadedResource.delete(value.dir);
                    }
                }
            });
        }
        //重置标记
        this._isLoading = false;
        this._loadedCount = 0;
        this._resources.clear();
    }

    private _onLoadResourceComplete(data: Resource.CacheData) {
        this._loadedCount++;

        if (this.onLoadProgress) {
            if (this._loadedCount > this._resources.size) {
                this._loadedCount = this._resources.size;
            }
            //cc.log(`----------loadprogress ${this._loadedCount} / ${this._resources.length}--------------`);
            this.onLoadProgress(this._loadedCount, this._resources.size, data);
        }

        if (data && (Array.isArray(data.data) || data.data instanceof c3d.Asset)) {
            //排除掉界面管理器
            let info = new Resource.Info({
                url: data.info.url, type: data.info.type, data: data.data, bundle: data.info.bundle
            });
            GM.assetMgr.retainAsset(info);
            this._loadedResource.set(info.url, info);
        }
        this.checkLoadResourceComplete();
    }

    /**  * 资源加载完成  */
    protected checkLoadResourceComplete() {
        //抛出事件给业务逻辑处理
        if (this.isLoadComplete()) {
            //加载完成
            this._isLoading = false;
            this.onLoadComplete && this.onLoadComplete(Resource.LoaderError.SUCCESS);
            this.onLoadResourceComplete();
        }
    }

    /**加载资源完成 */
    protected onLoadResourceComplete() {

    }

    isLoadComplete() {
        return this._loadedCount >= this._resources.size;
    }

}